<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Todo List 管理系统</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        :root {
            --primary-color: #4361ee;
            --success-color: #06d6a0;
            --warning-color: #ffd166;
            --danger-color: #ef476f;
            --light-color: #f8f9fa;
            --dark-color: #212529;
            --gray-color: #6c757d;
            --border-color: #dee2e6;
            --shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        }
        
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        
        body {
            background-color: #f5f7ff;
            color: var(--dark-color);
            line-height: 1.6;
        }
        
        .container {
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
        }
        
        header {
            text-align: center;
            margin-bottom: 30px;
            padding: 20px 0;
        }
        
        header h1 {
            font-size: 2.5rem;
            color: var(--primary-color);
            margin-bottom: 10px;
        }
        
        .card {
            background: white;
            border-radius: 10px;
            box-shadow: var(--shadow);
            padding: 25px;
            margin-bottom: 25px;
            position: relative;
        }
        
        .form-group {
            margin-bottom: 20px;
        }
        
        label {
            display: block;
            margin-bottom: 8px;
            font-weight: 600;
            color: var(--dark-color);
        }
        
        input, textarea, select {
            width: 100%;
            padding: 12px 15px;
            border: 1px solid var(--border-color);
            border-radius: 6px;
            font-size: 1rem;
            transition: border-color 0.3s;
        }
        
        input:focus, textarea:focus, select:focus {
            outline: none;
            border-color: var(--primary-color);
            box-shadow: 0 0 0 3px rgba(67, 97, 238, 0.2);
        }
        
        button {
            background: var(--primary-color);
            color: white;
            border: none;
            border-radius: 6px;
            padding: 12px 20px;
            font-size: 1rem;
            font-weight: 600;
            cursor: pointer;
            transition: background 0.3s;
        }
        
        button:hover {
            background: #3250d4;
        }
        
        button.danger {
            background: var(--danger-color);
        }
        
        button.danger:hover {
            background: #d32f5e;
        }
        
        button.success {
            background: var(--success-color);
        }
        
        button.success:hover {
            background: #05b58d;
        }
        
        .flex {
            display: flex;
            gap: 15px;
        }
        
        .filters {
            display: flex;
            justify-content: space-between;
            margin-bottom: 20px;
            flex-wrap: wrap;
            gap: 10px;
        }
        
        .filter-group {
            display: flex;
            gap: 10px;
            align-items: center;
        }
        
        .filter-btn {
            background: white;
            color: var(--gray-color);
            border: 1px solid var(--border-color);
            padding: 8px 15px;
        }
        
        .filter-btn.active {
            background: var(--primary-color);
            color: white;
            border-color: var(--primary-color);
        }
        
        .task-list {
            list-style: none;
        }
        
        .task-item {
            background: white;
            border-left: 4px solid var(--primary-color);
            border-radius: 6px;
            padding: 18px 20px;
            margin-bottom: 15px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
            transition: transform 0.3s;
        }
        
        .task-item:hover {
            transform: translateY(-3px);
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
        }
        
        .task-item.completed {
            border-left-color: var(--success-color);
            opacity: 0.8;
        }
        
        .task-content {
            flex-grow: 1;
        }
        
        .task-title {
            font-weight: 600;
            font-size: 1.1rem;
            margin-bottom: 5px;
            display: flex;
            align-items: center;
            gap: 10px;
        }
        
        .task-title input[type="checkbox"] {
            width: auto;
            margin-right: 10px;
        }
        
        .task-description {
            color: var(--gray-color);
            font-size: 0.95rem;
            margin-bottom: 8px;
        }
        
        .task-meta {
            display: flex;
            gap: 15px;
            font-size: 0.85rem;
            color: var(--gray-color);
        }
        
        .task-actions {
            display: flex;
            gap: 10px;
        }
        
        .task-btn {
            width: 36px;
            height: 36px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            background: var(--light-color);
            color: var(--gray-color);
            border: none;
            cursor: pointer;
            transition: all 0.3s;
        }
        
        .task-btn:hover {
            background: var(--primary-color);
            color: white;
        }
        
        .empty-state {
            text-align: center;
            padding: 40px 20px;
            color: var(--gray-color);
        }
        
        .empty-state i {
            font-size: 4rem;
            margin-bottom: 20px;
            color: #e9ecef;
        }
        
        .empty-state h3 {
            margin-bottom: 10px;
            color: var(--dark-color);
        }
        
        .status-badge {
            display: inline-block;
            padding: 4px 10px;
            border-radius: 20px;
            font-size: 0.8rem;
            font-weight: 600;
        }
        
        .status-pending {
            background: rgba(255, 209, 102, 0.2);
            color: #e6a400;
        }
        
        .status-completed {
            background: rgba(6, 214, 160, 0.2);
            color: #059669;
        }
        
        .notification {
            position: fixed;
            top: 20px;
            right: 20px;
            padding: 15px 25px;
            border-radius: 8px;
            color: white;
            font-weight: 600;
            box-shadow: var(--shadow);
            z-index: 1000;
            opacity: 0;
            transform: translateX(100%);
            transition: all 0.3s;
        }
        
        .notification.show {
            opacity: 1;
            transform: translateX(0);
        }
        
        .notification.success {
            background: var(--success-color);
        }
        
        .notification.error {
            background: var(--danger-color);
        }
        
        .loading-overlay {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(255, 255, 255, 0.8);
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 10px;
            z-index: 10;
            opacity: 0;
            pointer-events: none;
            transition: opacity 0.3s;
        }
        
        .loading-overlay.active {
            opacity: 1;
            pointer-events: all;
        }
        
        .spinner {
            width: 40px;
            height: 40px;
            border: 4px solid rgba(67, 97, 238, 0.2);
            border-top: 4px solid var(--primary-color);
            border-radius: 50%;
            animation: spin 1s linear infinite;
        }
        
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        
        @media (max-width: 768px) {
            .container {
                padding: 15px;
            }
            
            .filters {
                flex-direction: column;
            }
            
            .task-item {
                flex-direction: column;
                align-items: flex-start;
            }
            
            .task-actions {
                width: 100%;
                justify-content: flex-end;
                margin-top: 15px;
            }
            
            .flex {
                flex-direction: column;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1><i class="fas fa-tasks"></i> Todo List 管理系统</h1>
        
        </header>
        
        <div class="card">
            <div class="loading-overlay" id="form-loading">
                <div class="spinner"></div>
            </div>
            <h2><i class="fas fa-plus-circle"></i> 添加新任务</h2>
            <form id="task-form">
                <div class="form-group">
                    <label for="title">任务标题 *</label>
                    <input type="text" id="title" placeholder="输入任务标题" required>
                </div>
                
                <div class="form-group">
                    <label for="description">任务描述</label>
                    <textarea id="description" rows="3" placeholder="输入任务描述（可选）"></textarea>
                </div>
                
                <div class="flex">
                    <div class="form-group" style="flex: 1;">
                        <label for="priority">优先级</label>
                        <select id="priority">
                            <option value="low">低</option>
                            <option value="medium" selected>中</option>
                            <option value="high">高</option>
                        </select>
                    </div>
                    
                    <div class="form-group" style="flex: 1;">
                        <label for="category">分类</label>
                        <select id="category">
                            <option value="work">工作</option>
                            <option value="personal">个人</option>
                            <option value="study">学习</option>
                            <option value="health">健康</option>
                        </select>
                    </div>
                </div>
                
                <button type="submit" class="success">
                    <i class="fas fa-plus"></i> 添加任务
                </button>
            </form>
        </div>
        
        <div class="card">
            <div class="loading-overlay" id="list-loading">
                <div class="spinner"></div>
            </div>
            <div class="filters">
                <div class="filter-group">
                    <button class="filter-btn active" data-filter="all">全部</button>
                    <button class="filter-btn" data-filter="pending">进行中</button>
                    <button class="filter-btn" data-filter="completed">已完成</button>
                </div>
                
                <div class="form-group" style="width: 250px; margin-bottom: 0;">
                    <input type="text" id="search" placeholder="搜索任务...">
                </div>
            </div>
            
            <h2><i class="fas fa-list"></i> 任务列表</h2>
            <ul class="task-list" id="task-list">
                <!-- 任务将通过JavaScript动态添加 -->
            </ul>
        </div>
    </div>
    
    <div class="notification" id="notification"></div>
    
    <script>
        // 数据库API服务 - 使用MySQL数据库
        class TaskAPIService {
            constructor() {
                this.baseUrl = 'http://localhost:3000/api'; // 后端API地址
                this.currentFilter = 'all';
                this.searchTerm = '';
            }
            
            async _fetch(url, options = {}) {
                const response = await fetch(url, {
                    ...options,
                    headers: {
                        'Content-Type': 'application/json'
                    }
                });
                
                if (!response.ok) {
                    const error = await response.json();
                    throw new Error(error.message || '请求失败');
                }
                
                return response.json();
            }
            
            // 获取所有任务
            async getTasks() {
                const url = new URL(`${this.baseUrl}/tasks`);
                if (this.currentFilter !== 'all') {
                    url.searchParams.append('status', this.currentFilter);
                }
                if (this.searchTerm) {
                    url.searchParams.append('search', this.searchTerm);
                }
                
                return this._fetch(url);
            }
            
            // 创建新任务
            async createTask(taskData) {
                return this._fetch(`${this.baseUrl}/tasks`, {
                    method: 'POST',
                    body: JSON.stringify(taskData)
                });
            }
            
            // 更新任务
            async updateTask(id, updatedData) {
                return this._fetch(`${this.baseUrl}/tasks/${id}`, {
                    method: 'PUT',
                    body: JSON.stringify(updatedData)
                });
            }
            
            // 删除任务
            async deleteTask(id) {
                return this._fetch(`${this.baseUrl}/tasks/${id}`, {
                    method: 'DELETE'
                });
            }
            
            // 切换任务状态
            async toggleTaskStatus(id) {
                return this._fetch(`${this.baseUrl}/tasks/${id}/toggle`, {
                    method: 'PATCH'
                });
            }
            
            // 设置当前筛选器
            setFilter(filter) {
                this.currentFilter = filter;
            }
            
            // 设置搜索词
            setSearchTerm(term) {
                this.searchTerm = term;
            }
        }

        // UI渲染类
        class TaskRenderer {
            constructor() {
                this.taskList = document.getElementById('task-list');
                this.notification = document.getElementById('notification');
                this.formLoading = document.getElementById('form-loading');
                this.listLoading = document.getElementById('list-loading');
            }
            
            // 渲染任务列表
            renderTasks(tasks) {
                if (tasks.length === 0) {
                    this.renderEmptyState();
                    return;
                }
                
                this.taskList.innerHTML = '';
                tasks.forEach(task => {
                    this.taskList.appendChild(this.createTaskElement(task));
                });
            }
            
            // 创建任务元素
            createTaskElement(task) {
                const li = document.createElement('li');
                li.className = `task-item ${task.completed ? 'completed' : ''}`;
                li.dataset.id = task.id;
                
                // 任务内容
                const taskContent = document.createElement('div');
                taskContent.className = 'task-content';
                
                const title = document.createElement('div');
                title.className = 'task-title';
                
                const checkbox = document.createElement('input');
                checkbox.type = 'checkbox';
                checkbox.checked = task.completed;
                checkbox.addEventListener('change', () => TaskManager.toggleTaskStatus(task.id));
                
                title.appendChild(checkbox);
                title.appendChild(document.createTextNode(task.title));
                
                if (task.description) {
                    const description = document.createElement('p');
                    description.className = 'task-description';
                    description.textContent = task.description;
                    taskContent.appendChild(description);
                }
                
                // 任务元数据
                const meta = document.createElement('div');
                meta.className = 'task-meta';
                
                const priorityMap = {
                    'low': '低',
                    'medium': '中',
                    'high': '高'
                };
                
                const categoryMap = {
                    'work': '工作',
                    'personal': '个人',
                    'study': '学习',
                    'health': '健康'
                };
                
                const priority = document.createElement('span');
                priority.innerHTML = `<i class="fas fa-flag"></i> 优先级: ${priorityMap[task.priority]}`;
                
                const category = document.createElement('span');
                category.innerHTML = `<i class="fas fa-tag"></i> 分类: ${categoryMap[task.category]}`;
                
                meta.appendChild(priority);
                meta.appendChild(category);
                
                // 日期信息
                const createdAt = new Date(task.created_at).toLocaleString();
                const dateInfo = document.createElement('span');
                dateInfo.innerHTML = `<i class="fas fa-calendar"></i> 创建: ${createdAt}`;
                meta.appendChild(dateInfo);
                
                if (task.updated_at && task.updated_at !== task.created_at) {
                    const updatedAt = new Date(task.updated_at).toLocaleString();
                    const updateInfo = document.createElement('span');
                    updateInfo.innerHTML = `<i class="fas fa-sync-alt"></i> 更新: ${updatedAt}`;
                    meta.appendChild(updateInfo);
                }
                
                taskContent.appendChild(title);
                taskContent.appendChild(meta);
                
                // 任务操作
                const actions = document.createElement('div');
                actions.className = 'task-actions';
                
                const editBtn = document.createElement('button');
                editBtn.className = 'task-btn';
                editBtn.innerHTML = '<i class="fas fa-edit"></i>';
                editBtn.title = '编辑任务';
                editBtn.addEventListener('click', () => this.editTask(task));
                
                const deleteBtn = document.createElement('button');
                deleteBtn.className = 'task-btn danger';
                deleteBtn.innerHTML = '<i class="fas fa-trash"></i>';
                deleteBtn.title = '删除任务';
                deleteBtn.addEventListener('click', () => TaskManager.deleteTask(task.id));
                
                actions.appendChild(editBtn);
                actions.appendChild(deleteBtn);
                
                li.appendChild(taskContent);
                li.appendChild(actions);
                
                return li;
            }
            
            // 渲染空状态
            renderEmptyState() {
                this.taskList.innerHTML = `
                    <div class="empty-state">
                        <i class="fas fa-inbox"></i>
                        <h3>没有任务</h3>
                        <p>${this.currentFilter === 'all' ? 
                            '添加一个新任务开始吧！' : 
                            this.currentFilter === 'pending' ? 
                            '没有进行中的任务' : 
                            '没有已完成的任务'}</p>
                    </div>
                `;
            }
            
            // 显示通知
            showNotification(message, type = 'success') {
                const notification = this.notification;
                notification.textContent = message;
                notification.className = `notification ${type} show`;
                
                setTimeout(() => {
                    notification.classList.remove('show');
                }, 3000);
            }
            
            // 显示/隐藏加载状态
            showLoading(element, show = true) {
                if (show) {
                    element.classList.add('active');
                } else {
                    element.classList.remove('active');
                }
            }
            
            // 编辑任务
            editTask(task) {
                // 填充表单
                document.getElementById('title').value = task.title;
                document.getElementById('description').value = task.description || '';
                document.getElementById('priority').value = task.priority;
                document.getElementById('category').value = task.category;
                
                // 更改按钮行为
                const form = document.getElementById('task-form');
                const submitBtn = form.querySelector('button');
                submitBtn.innerHTML = '<i class="fas fa-save"></i> 更新任务';
                submitBtn.dataset.editing = task.id;
                
                // 滚动到表单
                form.scrollIntoView({ behavior: 'smooth' });
            }
            
            // 重置表单
            resetForm() {
                document.getElementById('task-form').reset();
                const submitBtn = document.querySelector('#task-form button');
                submitBtn.innerHTML = '<i class="fas fa-plus"></i> 添加任务';
                delete submitBtn.dataset.editing;
            }
        }

        // 任务管理类
        class TaskManager {
            static init() {
                this.api = new TaskAPIService();
                this.renderer = new TaskRenderer();
                
                // 加载任务
                this.loadTasks();
                
                // 事件监听
                document.getElementById('task-form').addEventListener('submit', this.handleFormSubmit.bind(this));
                document.querySelectorAll('.filter-btn').forEach(btn => {
                    btn.addEventListener('click', () => this.setFilter(btn.dataset.filter));
                });
                document.getElementById('search').addEventListener('input', (e) => {
                    this.api.setSearchTerm(e.target.value);
                    this.loadTasks();
                });
            }
            
            // 加载任务
            static async loadTasks() {
                try {
                    this.renderer.showLoading(this.renderer.listLoading, true);
                    const tasks = await this.api.getTasks();
                    this.renderer.renderTasks(tasks);
                } catch (error) {
                    this.renderer.showNotification(`加载任务失败: ${error.message}`, 'error');
                } finally {
                    this.renderer.showLoading(this.renderer.listLoading, false);
                }
            }
            
            // 处理表单提交
            static async handleFormSubmit(e) {
                e.preventDefault();
                
                const title = document.getElementById('title').value.trim();
                const description = document.getElementById('description').value.trim();
                const priority = document.getElementById('priority').value;
                const category = document.getElementById('category').value;
                const submitBtn = e.target.querySelector('button');
                
                if (!title) {
                    this.renderer.showNotification('任务标题不能为空', 'error');
                    return;
                }
                
                try {
                    this.renderer.showLoading(this.renderer.formLoading, true);
                    const taskData = { title, description, priority, category };
                    
                    // 如果是编辑任务
                    if (submitBtn.dataset.editing) {
                        const taskId = submitBtn.dataset.editing;
                        await this.api.updateTask(taskId, taskData);
                        this.renderer.showNotification('任务更新成功');
                    } 
                    // 如果是添加新任务
                    else {
                        await this.api.createTask(taskData);
                        this.renderer.showNotification('任务添加成功');
                    }
                    
                    this.renderer.resetForm();
                    this.loadTasks();
                } catch (error) {
                    this.renderer.showNotification(`操作失败: ${error.message}`, 'error');
                } finally {
                    this.renderer.showLoading(this.renderer.formLoading, false);
                }
            }
            
            // 设置筛选器
            static setFilter(filter) {
                this.api.setFilter(filter);
                
                // 更新按钮状态
                document.querySelectorAll('.filter-btn').forEach(btn => {
                    btn.classList.toggle('active', btn.dataset.filter === filter);
                });
                
                this.loadTasks();
            }
            
            // 切换任务状态
            static async toggleTaskStatus(id) {
                try {
                    await this.api.toggleTaskStatus(id);
                    this.renderer.showNotification('任务状态已更新');
                    this.loadTasks();
                } catch (error) {
                    this.renderer.showNotification(`更新状态失败: ${error.message}`, 'error');
                }
            }
            
            // 删除任务
            static async deleteTask(id) {
                if (!confirm('确定要删除这个任务吗？')) return;
                
                try {
                    await this.api.deleteTask(id);
                    this.renderer.showNotification('任务已删除');
                    this.loadTasks();
                } catch (error) {
                    this.renderer.showNotification(`删除失败: ${error.message}`, 'error');
                }
            }
        }

        // 初始化应用
        document.addEventListener('DOMContentLoaded', () => {
            TaskManager.init();
        });
    </script>
</body>
</html>